#!/usr/bin/env python
# coding=utf-8

if __name__ == '__main__':
    import sys,os
    sys.path.insert(0,os.path.abspath('..'))
    sys.path.insert(0,os.path.abspath('../../'))

from vavava.workshop import WorkShop
from vavava.dbworkshop import DBWorkshop
from vavava.basethread import BaseThread
from vavava.dispatcher import Dispatcher
from vavava.workqueue import Work
from DBUtils import PooledDB
import MySQLdb,time

class InitDispatcherThread(BaseThread):
    def __init__(self,log=None):
        BaseThread.__init__(self,name="InitDispatcherThread",log=log)
        self._groups = []
        self._works  = []
        self._dispatcher = Dispatcher()

    def start(self,groups,works,dsp):
        self._groups = groups
        self._works  = works
        self._dispatcher = dsp
        self.running_start()

    def stop(self,timeout=10):
        if self.IsAlive:
            self.running_stop()
            self.join(timeout=timeout)

    def run(self):
        while self.IsRunning:
            self.log.info("[%s] Begin to init dispatcher by groups=%d,works=%d.",
                self.getName(), len(self._groups), len(self._works) )
            del_groups = []
            del_works  = []
            for group in self._groups:
                group_id = "??"
                try:
                    group_id = group.group_id
                    self.log.info(r'[%s] Start group "%s" .', self.getName(), group.group_id )
                    ws = self._init_workshop(group)
                    self._dispatcher.AddWorkshop(ws,start=group.auto_start)
                    self.log.info(r'[%s] Start group "%s" succeed.', self.getName(), group.group_id )
                    del_groups.append(group)
                except Exception as e:
                    self.log.error("[%s] Failed to start workshop group_id=%s", self.getName(), group_id )
                    self.log.exception(e)

            for work in self._works:
                try:
                    if work.group_id not in self._works:
                        self.log.info(r'[%s] Start auto work "%s" .', self.getName(), work.name )
                        wk = self.add_work_from_string(work)
                        self._dispatcher.AddWork(wk)
                        self.log.info(r'[%s] Start auto work "%s" succeed.', self.getName(), work.name )
                    del_works.append(work)
                except MySQLdb.Error as e:
                    self.log.exception(e)
                except Exception as e:
                    self.log.warn("[%s] Error:add work to dispatcher." % (self.getName()) )
                    self.log.exception(e)
                    return

            for i in del_groups: self._groups.remove(i)
            for i in del_works: self._works.remove(i)

            if len(self._groups) == 0 and len(self._works) == 0:
                self.log.info("[%s] Init dispatcher end.", self.getName() )
                break
            else:
                self.log.warn("[%s] Try to init dispatcher by groups=%d,works=%d.",
                             self.getName(), len(self._groups), len(self._works) )
                time.sleep(1)


    def _init_workshop(self,group):
        try:
            dbpool=None
            ws  = None
            if group.db_support:
                dbpool = InitDispatcherThread.__get_dbpool(
                    minsize = group.db_pool_min,
                    maxsize = group.db_pool_max,
                    host    = group.host,
                    port    = group.port,
                    user    = group.user,
                    passwd  = group.password,
                    db      = group.db,
                    charset = group.charset
                )
                ws = DBWorkshop(
                    dbpool=dbpool,
                    group=group.group_id,
                    maxsize=None,
                    minsize=group.work_queue_size,
                    redoable_supoort=group.redoable_supoort,
                    priority_support=group.priority_support,
                    log=self.log,
                    parent=None
                )
            else:
                ws[group.group_id] = WorkShop(
                    group=group.group_id,
                    maxsize=None,
                    minsize=group.work_queue_size,
                    redoable_supoort=group.redoable_supoort,
                    priority_support=group.priority_support,
                    log=self.log,
                    parent=None
                )
            return ws
        except Exception as e:
            self.log.exception(e)

    def add_work_from_string(self,work):
        try:
            cls_name = work.type_path+"."+work.type_name
            pa = InitDispatcherThread.__importAny( cls_name )
            return pa(
                period     = work.period,
                group      = work.group_id,
                begin_time = work.begin_time,
                end_time   = work.end_time,
                log        = self.log,
                name       = work.name,
                *work.args,
                **work.kargs
            )
        except Exception as e:
            self.log.exception(e)

    @staticmethod
    def __importAny(name):
        try:
            return __import__(name,fromlist=[''])
        except:
            try:
                i = name.rfind('.')
                mod = __import__(name[:i],fromlist=[''])
                return getattr(mod,name[i+1:])
            except:
                raise RuntimeError('No module of: %s found'%(name))

    @staticmethod
    def __get_dbpool(minsize=10,maxsize=20,host='localhost',
                     port=55555,user='root',passwd='root',db='test',charset='utf8'):
        dbpool = PooledDB.PooledDB(
            creator=MySQLdb,
            mincached=minsize,
            maxcached=maxsize,
            maxshared=minsize,
            maxconnections=100,
            blocking=False,
            host=host,
            port=port,
            user=user,
            passwd=passwd,
            db=db,
            charset=charset
        )
        return dbpool
